﻿using System;
using System.Collections.Generic;
using System.IO;
using CSJ2K.Util.IO;

namespace CSJ2K.Jpc.Segments
{
    /// <summary>Coding style component (COC)</summary>
    /// <comment>
    /// Function: Describes the coding style and number of decomposition levels used for 
    ///      compressing a particular component. 
    /// Usage: Main and first tile-part header of a given tile. Optional in both the main 
    ///      and tile-part headers. No more than one per any given component may be present 
    ///      in either the main or tile-part headers. If there are multiple tile-parts in a 
    ///      tile, and this marker segment is present, it shall be found only in the first 
    ///      tile-part (TPsot = 0). When used in the main header, it overrides the main COD 
    ///      marker segment for the specific component. When used in the tile-part header, 
    ///      it overrides the main COD, main COC, and tile COD for the specific component. 
    ///      Thus, the order of precedence is the following: 
    ///          Tile-part COC > Tile-part COD > Main COC > Main COD 
    ///      where the "greater than" sign, >, means that the greater overrides the lessor 
    ///      marker segment. 
    /// Length: Variable depending on the value of Scoc. (and Csiz?!)
    /// </comment>
    public class COC : Segment
    {
        /// <summary>The index of the component to which this marker segment relates.</summary>
        public ushort C;

        /// <summary>Coding Style for this component</summary>
        public CodingStyles S;    

        public struct SPInfo
        {
            /// <summary>Number of decomposition levels</summary>
            public byte A;

            /// <summary>Code-block width</summary>
            public byte B;

            /// <summary>Code-block height</summary>
            public byte C;

            /// <summary>Code-block style</summary>
            public CodeBlockStyles D;

            /// <summary>Transformation</summary>
            public Transformations E;

            /// <summary>Precinct size</summary> 
            public byte[] F;               
        }
        /// <summary>Parameters for coding style designated in Scoc.</summary>
        public SPInfo SP = new SPInfo();

        public COC(Stream source, int components)
            : this(source, (Markers)StreamUtil.ReadBUInt16(source), components) { }
        public COC(Stream source, Markers marker, int components)
            : base(source, marker, true)
        {
            if (marker != Markers.COC) throw (new ApplicationException("Attempting to create segment of the wrong type."));

            if (components < 257) C = StreamUtil.ReadOctet(source);
            else C = StreamUtil.ReadBUInt16(source);

            S = (CodingStyles)StreamUtil.ReadOctet(source);

            SP.A = StreamUtil.ReadOctet(source);
            SP.B = StreamUtil.ReadOctet(source);
            SP.C = StreamUtil.ReadOctet(source);
            SP.D = (CodeBlockStyles)StreamUtil.ReadOctet(source);
            SP.E = (Transformations)StreamUtil.ReadOctet(source);

            if ((S & CodingStyles.Defined) == CodingStyles.Defined)
            {
                SP.F = StreamUtil.ReadBytes(source, SP.A);
            }
        }
    }
}
